package com.atguigu.yygh.user.controller.api;

import com.atguigu.yygh.common.exception.YyghException;
import com.atguigu.yygh.common.result.R;
import com.atguigu.yygh.common.result.ResultCode;
import com.atguigu.yygh.common.utils.JwtHelper;
import com.atguigu.yygh.enums.UserStatusEnum;
import com.atguigu.yygh.model.user.UserInfo;
import com.atguigu.yygh.user.service.UserInfoService;
import com.atguigu.yygh.user.utils.ConstantProperties;
import com.atguigu.yygh.user.utils.HttpClientUtils;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA
 *
 * @Date: 2022/12/29 - 15:50
 * @Author: Hyoung
 * @Description:
 */


@Api(tags = "微信扫码登录")
@Controller//注意这里没有配置 @RestController
@RequestMapping("/api/user/wx")
@Slf4j
public class ApiWxController {

    @Autowired
    private ConstantProperties constantProperties;

    @Autowired
    private UserInfoService userInfoService;

    /**
     * 方式一：在新的页面中展示登录二维码
     */
    @GetMapping("/getQRCodeUrl")
    public String getQRCodeUrl(HttpSession session) {
        try {
            //处理回调url
            String redirectUri = URLEncoder.encode(constantProperties.getRedirectUri(), "UTF-8");

            //处理state：生成随机数，存入session
            String state = UUID.randomUUID().toString();
            log.info("生成 state = " + state);
            session.setAttribute("wx_open_state", state);

            String qrcodeUrl = "https://open.weixin.qq.com/connect/qrconnect" +
                    "?appid=" + constantProperties.getAppId() +
                    "&redirect_uri=" + redirectUri +
                    "&response_type=code" +
                    "&scope=snsapi_login" +
                    "&state=" + state +
                    "#wechat_redirect";

            return "redirect:" + qrcodeUrl;

        } catch (Exception e) {
            throw new YyghException(20014, "生成二维码失败", e);
        }
    }

    /**
     * 登录回调
     *
     * @param code
     * @param state
     * @param session
     * @return
     */
    @GetMapping("/callback")
    public String callback(String code, String state, HttpSession session) {

        try {
            //得到授权临时票据code和state参数
            log.info("callback被调用");
            log.info("code = " + code);
            log.info("state = " + state);

            String sessionState = (String) session.getAttribute("wx_open_state");
            log.info("sessionState = " + sessionState);
            log.info("seesion_id = " + session.getId());

            if (StringUtils.isEmpty(code) || StringUtils.isEmpty(state) || !state.equals(sessionState)) {
                throw new YyghException(20015, "非法回调");
            }

            //向微信的资源服务器发起请求，获取access_token
            String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                    "?appid=" + constantProperties.getAppId() +
                    "&secret=" + constantProperties.getAppSecret() +
                    "&code=" + code +
                    "&grant_type=authorization_code";

            //使用httpclient发送请求
            String accesstokenInfo = HttpClientUtils.get(accessTokenUrl);
            log.info("accesstokenInfo：" + accesstokenInfo);

            Gson gson = new Gson();
            HashMap accesstokenInfoMap = gson.fromJson(accesstokenInfo, HashMap.class);

            //判断失败的响应
            if (accesstokenInfoMap.get("errcode") != null) {
                log.error("获取access_token失败");
                throw new YyghException(20016, "获取access_token失败");
            }


            //微信获取access_token响应成功
            String openid = (String) accesstokenInfoMap.get("openid");
            log.info("openid" + openid);
            String accessToken = (String) accesstokenInfoMap.get("access_token");

            //根据openid判断数据库是否存在当前用户信息
            UserInfo userInfo = userInfoService.selectWxInfoByOpenId(openid);
            log.info("userInfo" + userInfo);
            if (userInfo == null) { //不存在
                log.info("注册用户");

                userInfo = userInfoService.getUserInfo(gson, openid, accessToken);

            } else {
                if (userInfo.getStatus().equals(UserStatusEnum.LOCK.getStatus())) {
                    throw new YyghException(ResultCode.ERROR, "用户已禁用");
                }
            }

            //生成jwt字符串
            String token = JwtHelper.createToken(userInfo.getId(), userInfo.getName());

            //跳转到前端页面
            return "redirect:http://localhost:3000/" +
                    "?token=" + token +
                    "&name=" + URLEncoder.encode(userInfo.getName(), "utf-8") +
                    "&openid=" + openid +
                    "&phone=" + userInfo.getPhone();

        } catch (Exception e) {
            throw new YyghException(20015, "微信登录失败", e);
        }
    }


    /**
     * 方式二：在内嵌网页中展示登录二维码（获取微信登录参数并返回给前端，由前端显示二维码）
     */
    @GetMapping("/getQRCodeParams")
    @ResponseBody
    public R getQRCodeParams(HttpSession session) {
        try {
            //处理回调url
            String redirectUri = URLEncoder.encode(constantProperties.getRedirectUri(), "UTF-8");
            //处理state：生成随机数，存入session
            String state = UUID.randomUUID().toString();
            log.info("生成 state = " + state);
            session.setAttribute("wx_open_state", state);
            //组装前端需要的参数
            Map<String, Object> map = new HashMap<>();
            map.put("scope", "snsapi_login");
            map.put("appid", constantProperties.getAppId());
            map.put("redirectUri", redirectUri);
            map.put("state", state);
            return R.ok().data(map);
        } catch (Exception e) {
            throw new YyghException(20014, "生成二维码失败", e);
        }
    }
}